﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Windows.Forms;
using System.ComponentModel;
using System.Data;
using System.Text.RegularExpressions;
using Microsoft.VisualBasic;
using WINBASE.Utils;

namespace WINBASE.Controls
{
	public class WLCTextBox : TextBox
	{
		Control _listPopup;

		static int WM_PAINT = 0x000F;
		bool IsOnError = false;
		bool IsSystemMode = false;

		public string alphaCharPattern = "^[a-zA-Z ]";
		public string numericCharPattern = "[-0-9]";
		public string specialCharPattern = "^[@#$^_\\~\\`\\%\\/\\\\\\&\\?\\,\\'\\;\\:\\!\\-]";
		public string customPattern;

		public WLCTextBox()
		{
			InitializeComponent();
		}

		private void InitializeComponent()
		{
			this.SuspendLayout();
			// 
			// WLCTextBox
			// 
			this.BorderStyle = ButtonBorderStyle.None;
			this.TextChanged += new System.EventHandler(this.WLCTextBox_TextChanged);
			this.Enter += new System.EventHandler(this.WLCTextBox_Enter);
			this.KeyDown += new System.Windows.Forms.KeyEventHandler(this.WLCTextBox_KeyDown);
			this.KeyPress += new System.Windows.Forms.KeyPressEventHandler(this.WLCTextBox_KeyPress);
			this.Layout += new System.Windows.Forms.LayoutEventHandler(this.WLCTextBox_Layout);
			this.Leave += new System.EventHandler(this.WLCTextBox_Leave);
			this.Validated += new System.EventHandler(this.WLCTextBox_Validated);
			this.ResumeLayout(false);

		}

		#region Events

		void lsv_Click(object sender, EventArgs e)
		{
			ListView lsv = ((ListView)sender);
			if (lsv.SelectedItems.Count > 0)
			{
				this.Text = lsv.SelectedItems[0].Text;
				if (this.NameTextBox != null && (this.DisplayMember ?? "") != "")
				{
					this.NameTextBox.Text = lsv.SelectedItems[0].SubItems[1].Text;
				}
				lsv_KeyDown(lsv, new KeyEventArgs(Keys.Escape));
			}
		}

		void lst_Click(object sender, EventArgs e)
		{
			ListBox lst = ((ListBox)sender);
			if (lst.SelectedItems.Count > 0)
			{
				this.Text = lst.SelectedItem.ToString();
				lst_KeyDown(lst, new KeyEventArgs(Keys.Escape));
			}
		}

		void lst_KeyDown(object sender, KeyEventArgs e)
		{
			ListBox lst = ((ListBox)sender);
			switch (e.KeyCode)
			{
				case Keys.Enter:
					lst_Click(sender, null);
					break;

				case Keys.Escape:
					lst.Hide();
					this.Focus();
					break;
			}
		}

		void lsv_KeyDown(object sender, KeyEventArgs e)
		{
			ListView lsv = ((ListView)sender);
			switch (e.KeyCode)
			{
				case Keys.Enter:
					lsv_Click(sender, null);
					break;

				case Keys.Escape:
					lsv.Hide();
					this.Focus();
					break;
			}
		}

		private void WLCTextBox_Validated(object sender, EventArgs e)
		{
			//this.AssignData();
		}

		private void ParentLabelControl_MouseClick(object sender, MouseEventArgs e)
		{
			WLCTextBox_KeyDown(sender, new KeyEventArgs(Keys.F4));
		}

		private void WLCTextBox_KeyDown(object sender, KeyEventArgs e)
		{
			switch (e.KeyCode)
			{
				case Keys.F4:
					if (DisplayPopupForm)
					{
						ShowDialog();
					}
					else if (AutoCompleteAutoPopup)
					{
						//Load Data
						// via AutoCompleteCustomSource
						if (this.AutoCompleteCustomSource.Count > 0)
						{
							ListBox lst = new ListBox();
							lst.KeyDown += lst_KeyDown;
							lst.Click += lst_Click;
							lst.TabStop = false;
							this._listPopup = lst;
							if (this.NameTextBox != null)
							{
								lst.Width = this.NameTextBox.Right - this.Left;
							}
							else lst.Width = this.Width;
							lst.Height = 0;
							lst.ItemHeight = 15;
							lst.Location = new Point(this.Location.X, this.Location.Y + this.Height + 1);

							foreach (string str in this.AutoCompleteCustomSource)
							{
								lst.Items.Add(str);
								lst.Height += lst.ItemHeight;
							}

							this.Parent.Controls.Add(lst);
							lst.BringToFront();
							lst.Show();
						}
						else
						{
							// via View or Query
							ListView lsv = new ListView();
							lsv.KeyDown += lsv_KeyDown;
							lsv.Click += lsv_Click;
							lsv.TabStop = false;
							this._listPopup = lsv;
							if (this.NameTextBox != null)
							{
								lsv.Width = this.NameTextBox.Right - this.Left;
							}
							else lsv.Width = this.Width;
							lsv.Height = 20;
							lsv.View = View.Details;
							lsv.FullRowSelect = true;
							lsv.Location = new Point(this.Location.X, this.Location.Y + this.Height + 1);

							if ((DisplayMember ?? "") != "" && (ValueMember ?? "") != "")
							{
								lsv.Columns.Add("Code");
								lsv.Columns[0].Width = this.Width;
								lsv.Columns.Add("Name");
								lsv.Columns[1].Width = lsv.Width - lsv.Columns[0].Width - 5;

								foreach (DataRow dr in getData().Rows)
								{
									ListViewItem lsvItem = new ListViewItem(dr[ValueMember].ToString());
									lsvItem.SubItems.Add(dr[DisplayMember].ToString());
									lsv.Items.Add(lsvItem);
									lsv.Height += 20;
								}
								this.Parent.Controls.Add(lsv);
								lsv.BringToFront();
								lsv.Show();
								lsv.Focus();

								if (lsv.Items.Count > 0) lsv.Items[0].Selected = true;
							}
							else if ((ValueMember ?? "") != "")
							{
								lsv.Columns.Add("Code");
								lsv.Columns[0].Width = lsv.Width - 5;

								foreach (DataRow dr in getData().Rows)
								{
									ListViewItem lsvItem = new ListViewItem(dr[ValueMember].ToString());
									lsv.Items.Add(lsvItem);
									lsv.Height += 20;
								}
								this.Parent.Controls.Add(lsv);
								lsv.BringToFront();
								lsv.Show();
								lsv.Focus();

								if (lsv.Items.Count > 0) lsv.Items[0].Selected = true;
							}
						}
					}
					break;

				case Keys.Escape:
					if (_listPopup != null)
					{
						_listPopup.Hide();
						this.Focus();
					}
					break;
			}
		}

		private void ParentLabelControl_MouseHover(object sender, EventArgs e)
		{
			_ParentLabel.ForeColor = Color.Blue;
			_ParentLabel.Font = new Font(_ParentLabel.Font, FontStyle.Underline);
		}

		private void ParentLabelControl_MouseLeave(object sender, EventArgs e)
		{
			_ParentLabel.ForeColor = Color.Black;
			_ParentLabel.Font = new Font(_ParentLabel.Font, FontStyle.Regular);
		}

		private void WLCTextBox_KeyPress(object sender, KeyPressEventArgs e)
		{
			TextBox tb = (TextBox)sender;
			char chr = e.KeyChar;

			switch (this.CharacterType)
			{
				case CharacterType.Alphabetic:
					if (!Information.IsNumeric(e.KeyChar) & Regex.IsMatch(e.KeyChar.ToString(), alphaCharPattern))
					{
						//If adding the character to the end of the current TextBox value results in
						// a alphabetic char, go on. Otherwise, set e.Handled to True, and don't let
						// the character to be added.
						e.Handled = false;
					}
					else if (char.IsControl(e.KeyChar))
					{
						//IsControl is checked, because without that, keys like BackSpace couldn't
						// work correctly.
						e.Handled = false;
					}
					else
					{
						e.Handled = true;
					}

					break;
				case CharacterType.Numeric:
					if (Information.IsNumeric(e.KeyChar) & (e.KeyChar != '-'))
					{
						//If adding the character to the end of the current TextBox value results in
						// a numeric value, go on. Otherwise, set e.Handled to True, and don't let
						// the character to be added.
						e.Handled = !Information.IsNumeric(tb.Text + e.KeyChar);
					}
					else if (e.KeyChar == '.')
					{
						//For the decimal character (.) we need a different rule:
						//If adding a decimal to the end of the current value of the TextBox results
						// in a numeric value, it can be added. If not, this means we already have a
						// decimal in the TextBox value, so we only allow the new decimal to sit in
						// when it is overwriting the previous decimal.
						if (!(tb.SelectedText == "." | Information.IsNumeric(tb.Text + e.KeyChar)))
						{
							e.Handled = true;
						}
					}
					else if (e.KeyChar == '-')
					{
						//A negative sign is prevented if the "-" key is pressed in any location
						// other than the begining of the number, or if the number already has a
						// negative sign
						if (tb.SelectionStart != 0 | tb.Text.Left(1) == "-")
						{
							e.Handled = true;
						}
					}
					else if (!char.IsControl(e.KeyChar))
					{
						//IsControl is checked, because without that, keys like BackSpace couldn't
						// work correctly.
						e.Handled = true;
					}

					break;
				case CharacterType.SpecialChar:
					if (Regex.IsMatch(e.KeyChar.ToString(), specialCharPattern))
					{
						//If adding the character to the end of the current TextBox value results in
						// a special char, go on. Otherwise, set e.Handled to True, and don't let
						// the character to be added.
						e.Handled = false;
					}
					else if (char.IsControl(e.KeyChar))
					{
						//IsControl is checked, because without that, keys like BackSpace couldn't
						// work correctly.
						e.Handled = false;
					}
					else
					{
						e.Handled = true;
					}

					break;
				case CharacterType.AlphaNumeric:
					if (Information.IsNumeric(e.KeyChar) | Regex.IsMatch(e.KeyChar.ToString(), alphaCharPattern))
					{
						//If adding the character to the end of the current TextBox value results in
						// a alphabetic char or numeric value, go on. Otherwise, set e.Handled to True, and don't let
						// the character to be added.
						e.Handled = false;
					}
					else if (char.IsControl(e.KeyChar))
					{
						//IsControl is checked, because without that, keys like BackSpace couldn't
						// work correctly.
						e.Handled = false;
					}
					else
					{
						e.Handled = true;
					}

					break;
				case CharacterType.AlphaNumericSpecial:
					if (Information.IsNumeric(e.KeyChar) | Regex.IsMatch(e.KeyChar.ToString(), alphaCharPattern) | Regex.IsMatch(e.KeyChar.ToString(), specialCharPattern))
					{
						//If adding the character to the end of the current TextBox value results in
						// a alphabetic char, numeric value or special value, go on. Otherwise, set e.Handled to True, and don't let
						// the character to be added.
						e.Handled = false;
					}
					else if (char.IsControl(e.KeyChar))
					{
						//IsControl is checked, because without that, keys like BackSpace couldn't
						// work correctly.
						e.Handled = false;
					}
					else
					{
						e.Handled = true;
					}

					break;
				case CharacterType.Custom:
					if ((!string.IsNullOrEmpty(this._CustomCharcters.Trim())))
					{
						customPattern = "^[" + this._CustomCharcters + "]";
						if (Regex.IsMatch(e.KeyChar.ToString(), customPattern))
						{
							//If adding the character to the end of the current TextBox value results in
							// a special char, go on. Otherwise, set e.Handled to True, and don't let
							// the character to be added.
							e.Handled = false;
						}
						else if (char.IsControl(e.KeyChar))
						{
							//IsControl is checked, because without that, keys like BackSpace couldn't
							// work correctly.
							e.Handled = false;
						}
						else
						{
							e.Handled = true;
						}
					}
					else
					{
						e.Handled = false;
					}

					break;
				default:
					e.Handled = false;
					break;
			}
		}

		private void WLCTextBox_Leave(object sender, EventArgs e)
		{
			if (Site != null && Site.DesignMode) return;

			//Set Default Value Property
			if (this.Text.Trim() == "")
			{
				IsSystemMode = true;
				Text = _DefaultValue;
				IsSystemMode = false;
			}
		}

		private void WLCTextBox_Layout(object sender, LayoutEventArgs e)
		{
			if (Site != null && Site.DesignMode) return;

			//Set Default Value Property
			if (this.Text.Trim() == "")
			{
				IsSystemMode = true;
				Text = _DefaultValue;
				IsSystemMode = false;
			}
		}

		private void WLCTextBox_Enter(object sender, EventArgs e)
		{
			if (Site != null && Site.DesignMode) return;

			//Set Default Value Property
			if (this.Text.Trim() == _DefaultValue && !this.ReadOnly)
			{
				IsSystemMode = true;
				Text = "";
				IsSystemMode = false;
			}
		}

		#endregion

		#region Method

		public void AssignData()
		{
			if (((this.ViewName ?? "") != "" | (this.Query ?? "") != "") &
				(ValueMember ?? "") != "")
			{
				DataTable dt = getData();
				DataRow dr = (from row in dt.AsEnumerable()
							  where row[ValueMember].ToString() == this.Text.Trim()
							  select row).FirstOrDefault();

				if (dr != null)
				{
					//Assign Code and Name
					this.Text = dr[ValueMember].ToString();
					if (NameTextBox != null & (DisplayMember ?? "") != "")
					{
						NameTextBox.Text = dr[DisplayMember].ToString();
					}
					//Assign AdvanceBindingItem Text
					foreach (AdvanceBindingItem myAdvBindItem in AdvanceBinding)
					{
						myAdvBindItem.Control.Text = dr[myAdvBindItem.FieldName].ToString();
					}
					IsOnError = false;
					return;
				}
				else
				{
					if (NameTextBox != null)
					{
						NameTextBox.Text = "";
					}
					//Assign AdvanceBindingItem Text
					foreach (AdvanceBindingItem myAdvBindItem in AdvanceBinding)
					{
						myAdvBindItem.Control.Text = "";
					}
					IsOnError = true;
					return;
				}
			}
			else
			{
				IsOnError = false;
				return;
			}
		}

		public bool ValidateData()
		{
			if (!string.IsNullOrEmpty(this.Text.Trim()) & 
				((this.ViewName ?? "") != "" | (this.Query ?? "") != "") &
				(ValueMember ?? "") != "")
			{
				if (_CheckValidData)
				{
					DataTable dt = getData();
					int recCnt = (from row in dt.AsEnumerable()
								  where row[ValueMember].ToString() == this.Text.Trim()
								  select row.ItemArray).Count();
					if (recCnt > 0) return true;
					else return false;
				}
				else return true;
			}
			else
			{
				if (Mandatory)
				{
					if (!string.IsNullOrEmpty(this.Text.Trim()))
					{
						return true;
					}
					else return false;
				}
				else return true;
			}
		}

		//public void GetData()
		//{
		//    if ((this.Query ?? "") != "" | (this.ViewName ?? "") != "")
		//    {
		//        DataTable dt = (DataTable)this.getData();
		//        DataRow dr = (from row in dt.AsEnumerable()
		//                      where row[ValueMember].ToString() == this.Text.Trim()
		//                      select row).FirstOrDefault();

		//        if (dr != null)
		//        {
		//            //Assign Code and Name
		//            this.Text = dr[ValueMember].ToString();
		//            if (NameTextBox != null)
		//            {
		//                NameTextBox.Text = dr[DisplayMember].ToString();
		//            }
		//            //Assign AdvanceBindingItem Text
		//            foreach (AdvanceBindingItem myAdvBindItem in AdvanceBinding)
		//            {
		//                myAdvBindItem.Control.Text = dr[myAdvBindItem.FieldName].ToString();
		//            }
		//            isOnError = false;
		//            return;
		//        }
		//        else
		//        {
		//            isOnError = true;
		//            return;
		//        }
		//    }
		//    else
		//    {
		//        isOnError = false;
		//        return;
		//    }
		//}

		public DataTable getData()
		{
			if ((ViewName ?? "") != "")
			{
				return ApplicationService.QueryHelper.GetAView(this.ViewName);
			}
			else if ((Query ?? "") != "")
			{
				return ApplicationService.QueryHelper.GetADataTable(this.Query);
			}
			else return null;
		}

		WLCFrmSelectList frmSelectList;
		public DialogResult ShowDialog()
		{
			if ((this.ViewName ?? "") != "")
			{
				frmSelectList = new WLCFrmSelectList();
				frmSelectList.FormClosing += frmSelectList_FormClosing;

				frmSelectList.ViewName = this.ViewName;
				frmSelectList.QueryFilter = this.ViewFilter;
				frmSelectList.Text = this.ViewName;
				frmSelectList.InitializeData();
			}
			else
			{
				frmSelectList = new WLCFrmSelectList();
				frmSelectList.InitializeData(this.getData());
			}

			if (frmSelectList.ShowDialog() == DialogResult.OK)
			{
				if (frmSelectList.SelectedRow != null)
				{
					//Assign Code and Name
					IsSystemMode = true;
					_SelectedRow = frmSelectList.SelectedRow;
					this.Text = frmSelectList.SelectedRow[ValueMember].ToString();
					if (this.NameTextBox != null)
					{
						NameTextBox.Text = frmSelectList.SelectedRow[DisplayMember].ToString();
					}
					IsSystemMode = false;
				}
				
				//Assign AdvanceBindingItem Values
				if (frmSelectList.SelectedRow != null && AdvanceBinding != null)
				{
					IsSystemMode = true;
					foreach (AdvanceBindingItem myAdvBindItem in AdvanceBinding)
					{
						myAdvBindItem.Control.Text = frmSelectList.SelectedRow[myAdvBindItem.FieldName].ToString();
					}
					IsSystemMode = false;
				}
				return DialogResult.OK;
			}
			else
			{
				return DialogResult.Cancel;
			}
		}

		private void frmSelectList_FormClosing(object sender, FormClosingEventArgs e)
		{
			_SelectedRow = frmSelectList.SelectedRow;

			DialogEventArgs dlgEventArg = new DialogEventArgs();
			dlgEventArg.DialogResult = frmSelectList.DialogResult;
			OnDialogClose(this, dlgEventArg);
		}

		public event EventHandler DialogClose;
		protected virtual void OnDialogClose(object sender, DialogEventArgs e)
		{
			EventHandler handler = DialogClose;
			if (handler != null)
			{
				handler(sender, e);
			}
		}

		protected override void OnTextChanged(EventArgs e)
		{
			// raise event only if the control is in non-silent state
			if (!IsSystemMode)
			{
				base.OnTextChanged(e);
			}
		}

		protected override void WndProc(ref Message m)
		{
			base.WndProc(ref m);

			if (m.Msg == WM_PAINT)
			{
				Graphics g = Graphics.FromHwnd(Handle);
				Rectangle bounds = new Rectangle(0, 0, Width, Height);
				ControlPaint.DrawBorder(g, bounds, _BorderColor, _BorderStyle);
			}
		}

		#endregion

		#region Property

		private Color _BorderColor = Color.LightSlateGray;
		[Category("WINBASE"), Browsable(true), DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
		public Color BorderColor
		{
			get { return _BorderColor; }
			set
			{
				_BorderColor = value;
				Invalidate(); // causes control to be redrawn
			}
		}

		private ButtonBorderStyle _BorderStyle = ButtonBorderStyle.Solid;
		[Category("WINBASE"), Browsable(true), DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
		public ButtonBorderStyle BorderStyle
		{
			get { return _BorderStyle; }
			set
			{
				_BorderStyle = value;
				Invalidate();
			}
		}

		[Category("WINBASE"),Browsable(true), DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
		public bool Mandatory { get; set; }

		private bool _CheckValidData = true;
		[Category("WINBASE"), Browsable(true), DefaultValue(true), DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
		public bool CheckValidData
		{
			get { return _CheckValidData; }
			set { _CheckValidData = value; }
		}

		private string _DefaultValue = "";
		[Category("WINBASE"), Browsable(true), DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
		public string DefaultValue
		{
			get { return _DefaultValue; }
			set { _DefaultValue = value; }
		}

		private Label _ParentLabel = null;
		[Category("WINBASE"), Browsable(true), DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
		public Label ParentLabel
		{
			get { return _ParentLabel; }
			set
			{
				_ParentLabel = value;
				if (_ParentLabel != null)
				{
					this._ParentLabel.MouseClick += ParentLabelControl_MouseClick;
					this._ParentLabel.MouseHover += ParentLabelControl_MouseHover;
					this._ParentLabel.MouseLeave += ParentLabelControl_MouseLeave;
				}
			}
		}

		[Category("WINBASE"), Browsable(true), DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
		public TextBoxBase NameTextBox { get; set; }

		[Category("WINBASE"), DefaultValue(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
		public bool AutoCompleteAutoPopup { get; set; }

		[Category("WINBASE"), DefaultValue(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
		public bool DisplayPopupForm { get; set; }

		private List<AdvanceBindingItem> _AdvanceBinding = new List<AdvanceBindingItem>();
		[Category("WINBASE")]
		[Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
		public List<AdvanceBindingItem> AdvanceBinding 
		{ 
			get { return _AdvanceBinding; }
			set { _AdvanceBinding = value; }
		}

		private DataRow _SelectedRow;
		[Category("WINBASE")]
		[Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
		public DataRow SelectedRow
		{
			get { return _SelectedRow; }
		}

		[Category("WINBASE")]
		public string ViewName { get; set; }

		[Category("WINBASE")]
		public string ViewFilter { get; set; }

		[Category("WINBASE")]
		public string Query { get; set; }

		[Category("WINBASE")]
		public string DisplayMember { get; set; }

		[Category("WINBASE")]
		public string ValueMember { get; set; }

		private CharacterType _CharacterType = CharacterType.Neutral;
		[Category("WINBASE"), DefaultValue(CharacterType.Neutral)]
		public CharacterType CharacterType
		{
			get { return _CharacterType; }
			set { _CharacterType = value; }
		}

		private string _CustomCharcters = "";
		public string CustomCharcters
		{
			get { return _CustomCharcters; }
			set { _CustomCharcters = value; }
		}

		private int _MinLength = 0;
		[DefaultValue(0)]
		public int MinLength
		{
			get { return _MinLength; }
			set { _MinLength = value; }
		}

		#endregion

		private void WLCTextBox_TextChanged(object sender, EventArgs e)
		{
			if (!this.Focused)
			{
				if (this.Text == "" && (_DefaultValue ?? "") != "")
				{
					IsSystemMode = true;
					this.Text = _DefaultValue;
					IsSystemMode = false;
				}
			}
		}
	}

	[Serializable()]
	public class AdvanceBindingItem
	{
		private Control _Control;

		private string _FieldName;
		public AdvanceBindingItem(Control Control, string FieldName)
		{
			this.Control = Control;
			this.FieldName = FieldName;
		}

		public Control Control
		{
			get { return _Control; }
			set { _Control = value; }
		}

		public string FieldName
		{
			get { return _FieldName; }
			set { _FieldName = value; }
		}
	}

	public enum CharacterType
	{
		Neutral,
		Alphabetic,
		Numeric,
		AlphaNumeric,
		Date,
		DateTime,
		Time,
		SpecialChar,
		AlphaNumericSpecial,
		Custom
	}

	public class DialogEventArgs : EventArgs
	{
		public DialogResult DialogResult { get; set; }
	}
}